//	Solo funciona si las filas de la matriz de coeficientes no son Linealmente dependientes
#include <iostream>
#include <math.h>
#include <string.h>
#include <cstdlib>
#include <unistd.h>
using namespace std;

struct resistor{
	float r;
	float i;
	float v;
	float p;
	string sentido;
};

// muestra los elementos de la matriz en filas y columnas
// recibe una matriz de dimension 3x3 con elementos de punto flotante

void mostrar(float matriz[3][3]){			
	int i,j;
	cout << endl;
	for(i=0;i<3;i++){
		for(j=0;j<3;j++){
			cout << matriz[i][j] << "\t";
		}
		cout << endl;
	}
}

// muestra el contenido de un vector como una matriz columna
// acepta un vector de 3 elementos de tipo flotante

void mostrarvector(float V[3]){
	int i;
	for(i=0;i<3;i++){
		cout << V[i] << endl;
	}
}

// recibe un vector de 3 elementos de punto flotante
// acepta los valores de potencial en cada malla mediante el metodo cin y los almacena en el vector solicitado

void cargarvector(float vector[3]){
	int i;
	
	for(i=0;i<3;i++){
		cout << "Malla " << (i+1) << ": ";
		cin >> vector[i];
	}
}

// recibe un vector de estructuras tipo "resistor"
// acepta los valores de resistencia de cada resistor mediante el metodo cin y los almacena en un vector de estructuras resistor

void cargarresistencia(resistor vector[5]){	
	int i;
	for(i=0;i<5;i++){
		cout << "R" << (i+1) << "= ";
		cin >> vector[i].r;
	}
}
	
// recibe un vector de estructuras resistor y una matriz 3x3 de elementos float
// acomoda los valores correspondientes en la matriz de coeficientes para hacer la reduccion LU

void cargarmatriz(float matriz[3][3], resistor resistencias[5]){	
	int i,j;														
		
	for(i=0;i<3;i++){
		for(j=0;j<3;j++){
			if((j==2 && i==0)||(i==2 && j==0)){
				matriz[i][j]=0;
			}
			else{
				matriz[i][j]=resistencias[i+j].r;
			}
		}
	}
//hasta aca se copiaron las resistencias, falta sumar las resistencias de malla en los elementos de la diagonal principal	
	for(i=0;i<3;i++){
		for(j=0;j<3;j++){
			if(i!=j){	//evita sumar de nuevo el elemento de la diagonal principal
				matriz[i][i]+=matriz[i][j];
			}
		}
	}
//en este ultimo bucle se suman los elementos de toda la fila en la posicion [i][i], es decir se suman las resistencias de la malla en la diagonal principal
}

// recibe dos matrices 3x3 de tipo float
// compara todos los elementos de dos matrices devuelve
// devuelve un entero que vale 1 si son iguales o 0 si no lo son

int comparar(float m1[3][3],float m2[3][3]){	
	int i,j,iguales;
	iguales = 1;
	for(i=0;i<3;i++){
		for(j=0;j<3;j++){
			iguales=iguales * (m1[i][j]==m2[i][j]);
		}
	}
	return iguales;
}

//recibe dos matrices 3x3 de tipo flotante, orig=origen, dest=destino
//copia todos los elementos de una matriz dentro de otra con el mismo orden

void copiarmatriz(float orig[3][3], float dest[3][3]){ 
	int i,j;
	for(i=0;i<3;i++){
		for(j=0;j<3;j++){
			dest[i][j]=orig[i][j];
		}
	}
}

// recibe dos matrices 3x3 de tipo float
// la matriz M es la matriz de coeficientes del sistema
// reduce mediante el metodo de descomposicion LU
// y obtiene las matrices L y U pero las almacena en una sola llamada LU

void reducir(float LU[3][3],float M[3][3]){	
	int i,j,l,u,a;	
	l=0;
	copiarmatriz(M,LU);
	for (j=0;j<3;j++){	
		if (j!=0){	
			for (a=j;a<3;a++){					//aca se forma U
				for (u=j;u<3;u++){				//u es el indice de las columnas para recorrer la diagonal superior, a mueve las filas partiendo desde j
					LU[a][u] = LU[a][u] - (LU[a][l]*LU[j-1][u]);		//l avanza en cada iteracion del bucle global. De esta forma se reduce la matriz completa
					}
				}									//de a una columna por vez
			l++;
		}
		if (j+1 < 3){			//(j+1) evita que i valga mas de la dimension de la matriz
			for (i=j+1;i<3;i++){								//i son las filas, j las columnas.
				LU[i][j]=(LU[i][j] / LU[j][j]);		//estamos debajo de la diagonal principal, hay que hacer L
			}
		}
	}
}

// realiza el proceso de sustitucion hacia adelante para obtener el vector de resultados reducido
// recibe una matriz 3x3 float (la matriz L del sistema) y dos vectores de 3 elementos float. res=resultados, inc=incognitas

void sustad(float L[3][3],float res[3],float inc[3]){		
	int i,j;												
	float resta;											
	inc[0]=res[0];
	for	(i=1;i<3;i++){
		resta=0;
		for(j=0;j<i;j++){		//j se mueve debajo de la diagonal principal sin tocarla
			resta=resta+L[i][j]*inc[j];	//nunca se produce un error porque los res[i] ya estan solucionados y j siempre es menor a i
		}
		inc[i]=res[i]-resta;
	}
}

// realiza el proceso de sustitucion hacia atras para obtener el vector de resultados del sistema (vector incógnitas)
// acepta una matriz 3x3 float (la matriz U del sistema) y dos vectores de 3 elementos float, res=resultados, inc=incognitas

void sustat(float U[3][3],float res[3], float inc[3]){	
	int i,j;												
	float resta;											
	
	for(i=2;i>=0;i--){
		resta=0;
		for(j=i+1;j<3;j++){			//la primera vez no entra al bucle y resta vale cero, las demas veces se calcula resta
			resta=resta+(U[i][j]*inc[j]); //la primera vez no se ejecuta, las demas veces no hay error porque existe inc[j] para j=i+1
		}
		inc[i]=(res[i]-resta)/U[i][i];	//la primera vez resta vale 0 y no se tiene en cuenta, las demas veces se resta
	}
}

// decide que corriente (y con que sentido) circula por cada resistor
// recibe un vector de 5 elementos resistor y otro de 3 elementos float (corrientes de malla)

void asignari(resistor resistencia[5],float I[3]){		
	int j;													
	float aux;
	for(j=0;j<5;j++){
		resistencia[j].sentido="";
		if(pow(-1,j+1)<1){	//si la resistencia es de numero impar	(segun el dibujo)
		resistencia[j].i=sqrt(pow(I[j/2],2));
			if(I[j/2]<0){
				resistencia[j].sentido="←";
			}
			else if(I[j/2]>0){
				resistencia[j].sentido="→";
			}
		}
		else{				//la resistencia es de numero par	(segun el dibujo)
			aux = I[((j+1)/2)-1]-I[(j+1)/2];
			resistencia[j].i=sqrt(pow((aux),2));
			if((aux)<0){
				resistencia[j].sentido="↑";
			}
			else if((aux)>0){
				resistencia[j].sentido="↓";
			}
		}
//		cout << "R[" << j+1 << "].i=" << resistencia[j].i << " con sentido " << resistencia[j].sentido << endl; //descomentar linea para verificacion
	}
}

// aplica ley de ohm para obtener la dif de potencial a extremos de cada resistor
// recibe un vector de 5 elementos resistor de donde obtiene datos y almacena la informacion resultante

void calcularv(resistor resistencia[5]){					
	int j;
	for(j=0;j<5;j++){
		resistencia[j].v = resistencia[j].i * resistencia[j].r;
	}
}

// calcula la potencia que desarrolla cada resistor
// recibe un vector de 5 elementos resistor de donde obtiene datos y almacena la informacion resultante

void calcularp(resistor resistencia[5]){					
	int j;
	for(j=0;j<5;j++){
		resistencia[j].p = resistencia[j].v * resistencia[j].i;
	}
}

// ordena y muestra todos los resultados finales calculados, almacenados en el vector resistencia
// recibe un vector de 5 elementos resistor de donde obtiene los datos para mostrar por pantalla

void mostrarresultados(resistor resistencia[5]){			
	int j;													
	for(j=0;j<5;j++){
		cout << "Resistor " << j+1 << ":" << endl;
		cout << "R= " << resistencia[j].r << " Ω" << endl;
		cout << "I= " << resistencia[j].i << " A";
		if(resistencia[j].i != 0){
			cout << " con sentido " << resistencia[j].sentido << endl;
		}
		else {
			cout << endl;
		}
		cout << "V= " << resistencia[j].v << " V" << endl;
		cout << "P= " << resistencia[j].p << " W" << endl;
		cout << endl;
	}
}

int main(){
	
	float datos[3][3];
	float mdecoef[3][3];
	float Vdemalla[3];
	float LU[3][3];
	int flag=0;
	int iguales=0;
	string terminar;
	float Vreducida[3];
	float I[3];
	resistor R[5];
	
	system("clear");
	cout << "En este programa los valores son requeridos y entregados según la nomenclatura y dibujo dados por la consigna" << endl;
	usleep(3000000);
	while(terminar!="no"){
		terminar="";
		system("clear");
		cout << "Introduzca los valores de resistencia en Ohms de los resistores a la vez que se le solicita" << endl;
		cargarresistencia(R);
		cargarmatriz(datos,R);
		system("clear");
		cout << "A continuacion ingrese la suma de los potenciales, expresados en Volts, de las fuentes en el sentido de la corriente, de la malla correspondiente" << endl;
		cargarvector(Vdemalla);
		if (flag==0){
			copiarmatriz(datos,mdecoef);
			flag=1;
		}
		else {
			iguales = comparar(datos,mdecoef);
			if (iguales==0){
				copiarmatriz(datos,mdecoef);
			}
		}
		reducir(LU,mdecoef);
		sustad(LU,Vdemalla,Vreducida);
		sustat(LU,Vreducida,I);
		asignari(R,I);
		calcularv(R);
		calcularp(R);
		system("clear");
		cout << "La matriz LU obtenida es:" << endl;
		mostrar(LU);
		cout << endl;
		cout << "El vector de resultados reducido es:" << endl;
		mostrarvector(Vreducida);
		cout << endl << "El vector de corrientes de malla (solución del sistema) es:" << endl;
		mostrarvector(I);
		usleep(10000000);
		system("clear");
		mostrarresultados(R);
		while((terminar!="si")&&(terminar!="no")){
			cout << "¿Desea resolver otro circuito?: ";
			cin >> terminar;
			if ((terminar!="si")&&(terminar!="no")){
				cout << "por favor introduzca 'si' o 'no'" << endl;
			}
		}
	
	}
	cout << endl << "Alumno: Ariel Rabinovich" << endl << "Matricula: 36771223" << endl << "Año 2012" << endl << endl;
	return 0;
}
